using System;
using System.Collections.Generic;
using System.Text;

using XNAF = Microsoft.Xna.Framework;

using xBackend = XGAE.Framework.Backend;
using xBody = XGAE.Framework.Body;
using xExt = XGAE.Framework.Extensions;

using XGAE.Framework;

namespace XGAE.Body.Physics
{
    /// <summary>
    /// Base implementation for all the interfaces providing inline wrappers and convenient 
    /// access to the appropriate variables in the module.
    /// </summary>
    interface IPhysicsInterface
    {
        /// <summary>
        /// Wrappers to retrieve the backend from the module.
        /// </summary>
        xBackend.IPhysics Backend { get; }

        PhysicsModule Self { get; }
    }

    /// <summary>
    /// Collection of sensor queries that provide a notion of an animat's physical state.
    /// </summary>
    class PhysicsState : Interface, xBody.Physics.IState, IPhysicsInterface
    {
        #region Fields

        #region IPhysicsInterface Implementations

        protected PhysicsModule _self;

        public PhysicsModule Self
        {
            get { return this._self; }
        }

        public xBackend.IPhysics Backend
        {
            get { return _self.Backend; }
        }

        #endregion

        #endregion

        #region C'tors

        public PhysicsState(PhysicsModule m)
            : base("State", 0x0004)
        {
            _self = m;
        }

        #endregion

        #region IState Implementation

        /// <summary>
        /// Did a collision with a static or dynamic obstacle occur?
        /// </summary>
        /// <param name="normal"></param>
        /// <returns></returns>
        public virtual bool IsCollision(XNAF.Vector3 normal)
        {
            return this.Backend.IsCollision(normal);
        }

        /// <summary>
        /// Check the presence of a platform beneath us.
        /// </summary>
        /// <returns></returns>
        public virtual bool IsPlatform()
        {
            return (this.Backend.GetPlatform() != null);
        }

        /// <summary>
        /// Retrieve an entity for the platform below.
        /// </summary>
        /// <returns></returns>
        public virtual Entity GetPlatform()
        {
            return this.Backend.GetPlatform();
        }

        /// <summary>
        /// Is the agent currently holding onto a ladder?
        /// </summary>
        /// <returns></returns>
        public virtual bool IsLadder()
        {
            return this.Backend.IsLadder();
        }

        /// <summary>
        /// Are we in any kind of liquid?
        /// </summary>
        /// <returns></returns>
        public virtual bool IsWater()
        {
            return this.Backend.IsWater();
        }

        /// <summary>
        /// Check if the animat is touching the floor or not.
        /// </summary>
        /// <returns></returns>
        public virtual bool IsAir()
        {
            return this.Backend.IsAir();
        }

        #endregion
    }

    /// <summary>
    /// Sensor queries allowing the animat to perceive relative movement.
    /// </summary>
    class PhysicsRelative : Interface, xBody.Physics.IRelative, IPhysicsInterface  
    {
        #region Fields

        #region IPhysicsInterface Implementations

        protected PhysicsModule _self;

        public PhysicsModule Self
        {
            get { return this._self; }
        }

        public xBackend.IPhysics Backend
        {
            get { return _self.Backend; }
        }

        #endregion

        #endregion

        #region C'tors

        /// <summary>
        /// Constructor called by the module when it creates a new interface.
        /// </summary>
        /// <param name="m"></param>
        public PhysicsRelative(PhysicsModule m)
            : base("Relative", 0x0003)
        {
            this._self = m;
        }

        #endregion

        #region IRelative Implementation

        /// <summary>
        /// Odometric query to check how far we have gone relatively to the last position.
        /// </summary>
        /// <param name="movement"></param>
        public virtual void GetMovement(out XNAF.Vector3 movement)
        {
            _self.GetMovement(out movement);
        }

        /// <summary>
        /// Assertain how we've rotated from the previous position.
        /// </summary>
        /// <returns></returns>
        public virtual xExt.Angles GetOrientation()
        {
            return _self.GetOrientation();
        }

       /// <summary>
        /// The relative angle to zero pitch.
       /// </summary>
       /// <returns></returns>
        public virtual float GetBalance()
        {
            return _self.GOrientation.Pitch;
        }

        #endregion
    }

    /// <summary>
    /// Allow the other sensor and effector modules to convert relative commands into absolute
    /// world coordinates.
    /// </summary>
    class PhysicsConversion : Interface, xBody.Physics.IConversion, IPhysicsInterface  
    {
        #region Fields

        #region IPhysicsInterface Implementations

        protected PhysicsModule _self;

        public PhysicsModule Self
        {
            get { return this._self; }
        }

        public xBackend.IPhysics Backend
        {
            get { return _self.Backend; }
        }

        #endregion

        #endregion

        #region C'tors

        public PhysicsConversion(PhysicsModule m)
            : base("Conversion", 0x0001)
        {
            _self = m;
        }

        #endregion

        #region IConversion Implementations

        /// <summary>
        /// Provide the relative angles to restore the horizontal view.
        /// </summary>
        /// <param name="relative"></param>
        /// <param name="global"></param>
        public virtual void ToGlobal(XNAF.Vector3 relative, ref XNAF.Vector3 global)
        {
            global = XGAE.Helpers.Multiply(_self.MDirection, relative) + _self.GPosition;
        }

        /// <summary>
        /// Provide the relative angles to restore the horizontal view.
        /// </summary>
        /// <param name="global"></param>
        /// <param name="relative"></param>
        public virtual void ToRelative(XNAF.Vector3 global, ref XNAF.Vector3 relative)
        {
            relative = XGAE.Helpers.Multiply(_self.MInverse , (global - _self.GPosition));
        }

        #endregion
    }
}
